package com.analysis.service;

import com.analysis.model.AnalysisResponse;
import com.analysis.model.AnalysisResult;
import com.analysis.model.ClassDifference;
import com.analysis.model.MethodDifference;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.UnitValue;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

@Service
public class ExportService {

    public byte[] exportToExcel(AnalysisResponse response) throws IOException {
        if (!response.isSuccess() || response.getResult() == null) {
            throw new IllegalArgumentException("Invalid analysis response");
        }
        
        try (Workbook workbook = new XSSFWorkbook()) {
            // Create Summary sheet
            Sheet summarySheet = workbook.createSheet("Summary");
            createSummarySheet(summarySheet, response);

            // Create Changes sheet
            Sheet changesSheet = workbook.createSheet("Changes");
            createChangesSheet(changesSheet, response.getResult().getClassDifferences());

            // Create API Changes sheet
            Sheet apiSheet = workbook.createSheet("API Changes");
            createApiChangesSheet(apiSheet, response.getResult().getAffectedApis());

            // Write to byte array
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            workbook.write(outputStream);
            return outputStream.toByteArray();
        }
    }

    public byte[] exportToPdf(AnalysisResponse response) throws IOException {
        if (!response.isSuccess() || response.getResult() == null) {
            throw new IllegalArgumentException("Invalid analysis response");
        }

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        PdfWriter writer = new PdfWriter(outputStream);
        PdfDocument pdf = new PdfDocument(writer);
        Document document = new Document(pdf);

        // Add title
        document.add(new Paragraph("JAR Difference Analysis Report")
                .setFontSize(20)
                .setBold());

        // Add summary section
        addPdfSummarySection(document, response);

        // Add changes section
        addPdfChangesSection(document, response.getResult().getClassDifferences());

        // Add API changes section
        addPdfApiChangesSection(document, response.getResult().getAffectedApis());

        document.close();
        return outputStream.toByteArray();
    }

    private void createSummarySheet(Sheet sheet, AnalysisResponse response) {
        AnalysisResult result = response.getResult();
        
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("Analysis Summary");
        
        Row oldVersionRow = sheet.createRow(1);
        oldVersionRow.createCell(0).setCellValue("Old Version");
        oldVersionRow.createCell(1).setCellValue(response.getOldVersion());

        Row newVersionRow = sheet.createRow(2);
        newVersionRow.createCell(0).setCellValue("New Version");
        newVersionRow.createCell(1).setCellValue(response.getNewVersion());

        Row totalChangesRow = sheet.createRow(3);
        totalChangesRow.createCell(0).setCellValue("Total Changes");
        totalChangesRow.createCell(1).setCellValue(result.getClassDifferences().size());

        Row analysisTimeRow = sheet.createRow(4);
        analysisTimeRow.createCell(0).setCellValue("Analysis Time (ms)");
        analysisTimeRow.createCell(1).setCellValue(result.getAnalysisTime());

        Row totalClassesRow = sheet.createRow(5);
        totalClassesRow.createCell(0).setCellValue("Total Classes");
        totalClassesRow.createCell(1).setCellValue(result.getTotalClasses());

        Row modifiedClassesRow = sheet.createRow(6);
        modifiedClassesRow.createCell(0).setCellValue("Modified Classes");
        modifiedClassesRow.createCell(1).setCellValue(result.getModifiedClasses());

        Row addedClassesRow = sheet.createRow(7);
        addedClassesRow.createCell(0).setCellValue("Added Classes");
        addedClassesRow.createCell(1).setCellValue(result.getAddedClasses());

        Row deletedClassesRow = sheet.createRow(8);
        deletedClassesRow.createCell(0).setCellValue("Deleted Classes");
        deletedClassesRow.createCell(1).setCellValue(result.getDeletedClasses());

        // Auto-size columns
        sheet.autoSizeColumn(0);
        sheet.autoSizeColumn(1);
    }

    private void createChangesSheet(Sheet sheet, List<ClassDifference> differences) {
        // Create header row
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("Class Name");
        headerRow.createCell(1).setCellValue("Change Type");
        headerRow.createCell(2).setCellValue("Method Name");
        headerRow.createCell(3).setCellValue("Method Change Type");
        headerRow.createCell(4).setCellValue("Is API Method");

        int rowNum = 1;
        for (ClassDifference classDiff : differences) {
            for (MethodDifference methodDiff : classDiff.getMethodDifferences()) {
                Row row = sheet.createRow(rowNum++);
                row.createCell(0).setCellValue(classDiff.getClassName());
                row.createCell(1).setCellValue(classDiff.getType().toString());
                row.createCell(2).setCellValue(methodDiff.getMethodName());
                row.createCell(3).setCellValue(methodDiff.getType().toString());
                row.createCell(4).setCellValue(methodDiff.isApiMethod());
            }
        }

        // Auto-size columns
        for (int i = 0; i < 5; i++) {
            sheet.autoSizeColumn(i);
        }
    }

    private void createApiChangesSheet(Sheet sheet, Map<String, List<String>> affectedApis) {
        // Create header row
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("Class Name");
        headerRow.createCell(1).setCellValue("Affected APIs");

        int rowNum = 1;
        for (Map.Entry<String, List<String>> entry : affectedApis.entrySet()) {
            Row row = sheet.createRow(rowNum++);
            row.createCell(0).setCellValue(entry.getKey());
            row.createCell(1).setCellValue(String.join(", ", entry.getValue()));
        }

        // Auto-size columns
        sheet.autoSizeColumn(0);
        sheet.autoSizeColumn(1);
    }

    private void addPdfSummarySection(Document document, AnalysisResponse response) {
        AnalysisResult result = response.getResult();
        
        document.add(new Paragraph("Summary").setFontSize(16).setBold());
        Table table = new Table(2).setWidth(UnitValue.createPercentValue(100));
        
        table.addCell("Old Version");
        table.addCell(response.getOldVersion());
        
        table.addCell("New Version");
        table.addCell(response.getNewVersion());
        
        table.addCell("Total Changes");
        table.addCell(String.valueOf(result.getClassDifferences().size()));
        
        table.addCell("Analysis Time (ms)");
        table.addCell(String.valueOf(result.getAnalysisTime()));
        
        table.addCell("Total Classes");
        table.addCell(String.valueOf(result.getTotalClasses()));
        
        table.addCell("Modified Classes");
        table.addCell(String.valueOf(result.getModifiedClasses()));
        
        table.addCell("Added Classes");
        table.addCell(String.valueOf(result.getAddedClasses()));
        
        table.addCell("Deleted Classes");
        table.addCell(String.valueOf(result.getDeletedClasses()));
        
        document.add(table);
    }

    private void addPdfChangesSection(Document document, List<ClassDifference> differences) {
        document.add(new Paragraph("Changes").setFontSize(16).setBold());
        Table table = new Table(5).setWidth(UnitValue.createPercentValue(100));
        
        // Add header
        table.addCell("Class Name");
        table.addCell("Change Type");
        table.addCell("Method Name");
        table.addCell("Method Change Type");
        table.addCell("Is API Method");

        // Add data
        for (ClassDifference classDiff : differences) {
            for (MethodDifference methodDiff : classDiff.getMethodDifferences()) {
                table.addCell(classDiff.getClassName());
                table.addCell(classDiff.getType().toString());
                table.addCell(methodDiff.getMethodName());
                table.addCell(methodDiff.getType().toString());
                table.addCell(String.valueOf(methodDiff.isApiMethod()));
            }
        }
        
        document.add(table);
    }

    private void addPdfApiChangesSection(Document document, Map<String, List<String>> affectedApis) {
        document.add(new Paragraph("API Changes").setFontSize(16).setBold());
        Table table = new Table(2).setWidth(UnitValue.createPercentValue(100));
        
        // Add header
        table.addCell("Class Name");
        table.addCell("Affected APIs");

        // Add data
        for (Map.Entry<String, List<String>> entry : affectedApis.entrySet()) {
            table.addCell(entry.getKey());
            table.addCell(String.join(", ", entry.getValue()));
        }
        
        document.add(table);
    }
}
